package cn.xopencode.oss.manager.permission;

import cn.xopencode.common.framework.vo.CommonResult;
import cn.xopencode.oss.convert.permission.ResourceConvert;
import cn.xopencode.oss.enums.permission.ResourceIdEnum;
import cn.xopencode.oss.rpc.permission.vo.ResourceTreeNodeVO;
import cn.xopencode.oss.service.permission.ResourceServiceImpl;
import cn.xopencode.oss.service.permission.PositionService;
import cn.xopencode.oss.rpc.permission.dto.ResourceCreateDTO;
import cn.xopencode.oss.rpc.permission.dto.ResourceUpdateDTO;
import cn.xopencode.oss.rpc.permission.vo.ResourceVO;
import cn.xopencode.oss.service.permission.bo.ResourceBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static cn.xopencode.common.framework.vo.CommonResult.success;

/**
* 资源 Manager
*/
@Slf4j
@Service
public class ResourceManager {

    @Autowired
    private ResourceServiceImpl resourceService;
    @Autowired
    private PositionService positionService;

    /**
    * 创建资源
    *
    * @param createDTO 创建资源 DTO
    * @return 资源
    */
    public String createResource(ResourceCreateDTO createDTO) {
        ResourceBO resourceBO = resourceService.createResource(ResourceConvert.INSTANCE.convert(createDTO));
        return resourceBO.getId();
    }

    /**
     * 更新资源
     *
     * @param updateDTO 更新资源 DTO
     */
    public void updateResource(ResourceUpdateDTO updateDTO) {
        resourceService.updateResource(ResourceConvert.INSTANCE.convert(updateDTO));
    }

    /**
     * 删除资源
     *
     * @param resourceId 资源编号
     */
    public void deleteResource(String resourceId) {
        resourceService.deleteResource(resourceId);
    }

    /**
     * 获得资源
     *
     * @param resourceId 资源编号
     * @return 资源
     */
    public ResourceVO getResource(String resourceId) {
        ResourceBO resourceBO = resourceService.getResource(resourceId);
        return ResourceConvert.INSTANCE.convert(resourceBO);
    }

    /**
     * 获得资源全列表
     *
     * @return 资源列表
     */
    public List<ResourceVO> listResources() {
        List<ResourceBO> resourceBOs = resourceService.listResources();
        return ResourceConvert.INSTANCE.convertList02(resourceBOs);
    }

    /**
     * 获得资源列表
     *
     * @param resourceIds 资源编号列表
     * @return 资源列表
     */
    public List<ResourceVO> listResources(List<String> resourceIds) {
        List<ResourceBO> resourceBOs = resourceService.listResources(resourceIds);
        return ResourceConvert.INSTANCE.convertList02(resourceBOs);
    }

    /**
     * 获得指定职务的资源列表
     *
     * @param positionIds 职务编号列表
     * @param type 资源类型，允许空
     * @return 资源列表
     */
    public List<ResourceVO> listPositionResources(Collection<String> positionIds, Integer type) {
        List<ResourceBO> resourceBOs;
        // 判断是否为超管。若是超管，默认有所有权限
        if (positionService.hasSuperAdmin(positionIds)) {
            resourceBOs = resourceService.listResourcesByType(type);
        } else {
            resourceBOs = resourceService.listPositionResourcesByType(positionIds, type);
        }
        return ResourceConvert.INSTANCE.convertList02(resourceBOs);
    }
    /**
     * 获得资源树结构
     *
     * @return 资源树结构
     */
    public List<ResourceTreeNodeVO> treeResource() {
        // 获得资源全列表
        List<ResourceVO> resourceVOS = listResources();
        // 构建菜单树
        return buildResourceTree(resourceVOS);
    }
    /**
     * 构建资源树
     *
     * @param resourceVOs 资源列表
     * @return 资源树
     */
    public static List<ResourceTreeNodeVO> buildResourceTree(List<ResourceVO> resourceVOs) {
        // 排序，保证菜单的有序性
        resourceVOs.sort(Comparator.comparing(ResourceVO::getSort));
        // 构建菜单树
        // 使用 LinkedHashMap 的原因，是为了排序 。实际也可以用 Stream API ，就是太丑了。
        Map<String, ResourceTreeNodeVO> treeNodeMap = new LinkedHashMap<>();
        resourceVOs.forEach(resourceVO -> treeNodeMap.put(resourceVO.getId(), ResourceConvert.INSTANCE.convertTreeNode(resourceVO)));
        // 处理父子关系
        treeNodeMap.values().stream().filter(node -> !node.getPid().equals(ResourceIdEnum.ROOT.getId())).forEach((childNode) -> {
            // 获得父节点
            ResourceTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid());
            if (parentNode == null) {
                log.error("[buildResourceTree][resource({}) 找不到父资源({})]", childNode.getId(), childNode.getPid());
                return;
            }
            // 将自己添加到父节点中
            if (parentNode.getChildren() == null) {
                parentNode.setChildren(new ArrayList<>());
            }
            parentNode.getChildren().add(childNode);
        });
        // 获得到所有的根节点
        return treeNodeMap.values().stream().filter(node -> node.getPid().equals(ResourceIdEnum.ROOT.getId())).collect(Collectors.toList());
    }
}
